/////////////////////////////////////////////////////////////////////////
// 词法分析
// 本节没有提供词法分析器，直接提供了一个Token串。
// 语法分析程序可以从Token串中依次读出一个个Token，也可以重新定位Token串的当前读取位置。

use std::fmt;

//Token的类型
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum TokenKind{
	Keyword,
	Identifier,
	StringLiteral,
	Seperator,
	Operator,
	EOF
}

impl PartialEq for TokenKind {
    fn eq(&self, other :&TokenKind) -> bool {
        *self as i32 == *other as i32
    }
}

const TOKE_KIND_NAME: [&'static str; 6] = ["Keyword", "Identifier", "StringLiteral", "Seperator", "Operator", "EOF",];
impl fmt::Display for TokenKind{
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", TOKE_KIND_NAME[*self as usize])
    }
}

// 代表一个Token的数据结构
pub struct Token  {
	pub kind: TokenKind,
	pub text: String
}

impl fmt::Display for Token{
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "(Kind={}, Text={})", self.kind, self.text)
    }
}

impl Clone for Token{
	fn clone(&self) -> Token{
		Token::new_from_string(self.kind.clone(), self.text.clone())
	}
}

impl Token{
	pub fn new_from_string(kind: TokenKind, text: String) -> Token {
		Token{
			kind: kind,
			text: text
		}
	}

	pub fn new(kind: TokenKind, text: &str) -> Token {
		Token{
			kind: kind,
			text: String::from(text)
		}
	}
}

pub const EMPTY_CHAR:char = '\u{0}';

/**
 * 一个字符串流。其操作为：
 * peek():预读下一个字符，但不移动指针；
 * next():读取下一个字符，并且移动指针；
 * eof():判断是否已经到了结尾。
 */
pub struct CharStream  {
	data:String,
	pos:usize,      //当前读到的位置
	line:usize,     //行号
	col:usize,      //列号
	pre_pos:usize,  //当前读到的位置
	pre_line:usize, //行号
	pre_col:usize   //列号
}

impl CharStream{
	pub fn new(data:String) -> CharStream {
		CharStream{
			pos:  0,
			line: 1,
			col:  0,
			data: data,
			pre_pos:  0,
			pre_line: 1,
			pre_col:  0,
		}
	}

	pub fn peek(&self) -> char {
		if self.eof() {
			return EMPTY_CHAR;
		}

		return self.data.chars().nth(self.pos).unwrap();
	}

	pub fn next(&mut self)  -> char {
		if self.eof() {
			return EMPTY_CHAR;
		}

		self.pos+=1;
		let ch = self.data.chars().nth(self.pos-1).unwrap();
		if ch == '\n' {
			self.line+=1;
			self.col = 0;
		} else {
			self.col+=1;
		}
		return ch;
	}

	pub fn eof(&self) -> bool {
		return self.pos >= self.data.len();
	}

	pub fn record_pos(&mut self){
		self.pre_pos = self.pos;
		self.pre_line = self.line;
		self.pre_col = self.col;
	}

	pub fn rollback_pos(&mut self){
		self.pos = self.pre_pos;
		self.line = self.pre_line;
		self.col = self.pre_col;
	}
}

/**
 * 词法分析器
 * 语法分析器从这里获取Token。
 * 词法分析器的接口像是一个流，词法解析是按需进行的。
 * 支持下面两个操作：
 * next(): 返回当前的Token，并移向下一个Token。
 * peek(): 预读当前的Token，但不移动当前位置。
 */
pub struct Tokenizer  {
	stream     :CharStream,
	next_token :Token,
	pre_next_token  :Token
}

impl Tokenizer{
	pub fn new(stream:CharStream) ->Tokenizer {
		let eof_token:Token = Token::new(TokenKind::EOF, "");

		Tokenizer{
			next_token: eof_token.clone(),
			stream:     stream,
			pre_next_token:  eof_token
		}
	}

	pub fn next(&mut self) -> Token {
		if self.next_token.kind == TokenKind::EOF && !self.stream.eof() {
			//在第一次的时候，先parse一个Token
			self.next_token = self.get_a_token();
		}
		let last_token = self.next_token.clone();

		//往前走一个Token
		self.next_token = self.get_a_token();
		return last_token;
	}

	pub fn peek(&mut self) -> Token {
		if self.next_token.kind == TokenKind::EOF && !self.stream.eof() {
			//在第一次的时候，先parse一个Token
			self.next_token = self.get_a_token();
		}
		return self.next_token.clone();
	}

	pub fn record_pos(&mut self){
		self.pre_next_token = self.next_token.clone();
		self.stream.record_pos();
	}

	pub fn rollback_pos(&mut self) {
		self.next_token = self.pre_next_token.clone();
		self.stream.rollback_pos();
	}

	//从字符串流中获取一个新Token。
	fn get_a_token(&mut self) -> Token {
		self.skip_white_spaces();
		if self.stream.eof() {
			//EOF
			return Token::new(TokenKind::EOF, "");
		} else {
			let ch:char = self.stream.peek();
			if self.is_letter(ch) || self.is_digit(ch) {
				//标识符
				return self.parse_identifer();
			} else if ch == '"' {
				//字符串处理
				return self.parse_string_literal()
			} else if ch == '(' || ch == ')' || ch == '{' ||
				ch == '}' || ch == ';' || ch == ',' {
				//分隔符处理，包括括号，花括号，逗号，分号
				self.stream.next();
				return Token::new_from_string(TokenKind::Seperator, ch.to_string());
			} else if ch == '/' {
				//操作符/、/=
				//单行注释符//
				//多行注释符/*
				self.stream.next();
				let ch1 = self.stream.peek();
				if ch1 == '*' {
					self.skip_multiple_line_comments();
					return self.get_a_token();
				} else if ch1 == '/' {
					self.skip_single_line_comment();
					return self.get_a_token();
				} else if ch1 == '=' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "/=");
				} else {
					return Token::new(TokenKind::Operator, "/");
				}
			} else if ch == '+' {
				//操作符+、++、+=
				self.stream.next();
				let ch1 = self.stream.peek();
				if ch1 == '+' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "++");
				} else if ch1 == '=' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "+=");
				} else {
					return Token::new(TokenKind::Operator, "+");
				}
			} else if ch == '-' {
				//操作符-、--、-=
				self.stream.next();
				let ch1 = self.stream.peek();
				if ch1 == '-' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "--");
				} else if ch1 == '=' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "-=");
				} else {
					return Token::new(TokenKind::Operator, "-");
				}
			} else if ch == '*' {
				//操作符*、*=
				self.stream.next();
				let ch1 = self.stream.peek();
				if ch1 == '=' {
					self.stream.next();
					return Token::new(TokenKind::Operator, "*=");
				} else {
					return Token::new(TokenKind::Operator, "*");
				}
			} else {
				if ch == '\n' || ch == '\r' {
					//换行符不处理
				} else {
					//暂时去掉不能识别的字符
					println!("Unrecognized pattern meeting :{}, at {}, col: {}", ch, self.stream.line, self.stream.col);
				}
				self.stream.next();
				return self.get_a_token();
			}
		}
	}

	/**
	 * 跳过单行注释
	 */
	fn skip_single_line_comment(&mut self) {
		//跳过第二个/，第一个之前已经跳过去了。
		self.stream.next();

		//往后一直找到回车或者eof
		while self.stream.peek()!='\n' && !self.stream.eof() {
			self.stream.next();
		}
	}

	/**
	 * 跳过多行注释
	 */
	fn skip_multiple_line_comments(&mut self) {
		//跳过*，/之前已经跳过去了。
		self.stream.next();

		if !self.stream.eof() {
			let mut ch1 = self.stream.next();
			//往后一直找到回车或者eof
			while !self.stream.eof() {
				let ch2 = self.stream.next();
				if ch1 == '*' && ch2 == '/' {
					return;
				}
				ch1 = ch2;
			}
		}

		//如果没有匹配上，报错。
		println!("Failed to find matching */ for multiple line comments at line:{} col:{} ", self.stream.line, self.stream.col)
	}

	/**
	 * 跳过空白字符
	 */
	fn skip_white_spaces(&mut self) {
		while self.is_white_space(self.stream.peek()) {
			self.stream.next();
		}
	}

	/**
	 * 字符串字面量。
	 * 目前只支持双引号，并且不支持转义。
	 */
	fn parse_string_literal(&mut self) ->Token {
		let mut token:Token = Token::new(TokenKind::StringLiteral, "");

		//第一个字符不用判断，因为在调用者那里已经判断过了
		self.stream.next();

		//不断读取字符
		while !self.stream.eof() && self.stream.peek() != '"' {
			token.text.push(self.stream.next());
		}

		if self.stream.peek() == '"' {
			//消化掉字符换末尾的引号
			self.stream.next();
		} else {
			//找不到结束的引号
			println!("Expecting an \" at line:{} col:{} ", self.stream.line,  self.stream.col);
		}

		return token;
	}

	/**
	 * 解析标识符。从标识符中还要挑出关键字。
	 */
	fn parse_identifer(&mut self) -> Token {
		let mut token:Token = Token::new(TokenKind::Identifier, "");

		//第一个字符不用判断，因为在调用者那里已经判断过了
		token.text.push(self.stream.next());

		//读入后序字符
		while !self.stream.eof() &&  self.is_letter_digit_or_underscore(self.stream.peek()) {
			token.text.push(self.stream.next());
		}

		//识别出关键字，并进行处理
		if token.text == "function" {
			token.kind = TokenKind::Keyword;
		}

		return token;
	}

	//字母、数字、下划线、点
	fn is_letter_digit_or_underscore(&self, ch:char) -> bool {
		return ch >= 'A' && ch <= 'Z' ||
			ch >= 'a' && ch <= 'z' ||
			ch >= '0' && ch <= '9' ||
			ch == '_' || ch == '.';
	}

	//字母
	fn is_letter(&self, ch:char) ->  bool {
		return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z';
	}

	//数字
	fn is_digit(&self, ch:char) ->  bool {
		return ch >= '0' && ch <= '9';
	}

	//空格
	fn is_white_space(&self, ch:char) -> bool {
		return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
	}
}